package com.fjwt.gz.coupon.wx;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.fjwt.gz.core.config.WxProperties;
import com.fjwt.gz.core.third.bo.AwardCouponBo;
import com.github.binarywang.wxpay.bean.marketing.*;
import com.github.binarywang.wxpay.bean.marketing.enums.StockTypeEnum;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.github.binarywang.wxpay.v3.auth.AutoUpdateCertificatesVerifier;
import com.github.binarywang.wxpay.v3.auth.PrivateKeySigner;
import com.github.binarywang.wxpay.v3.auth.WxPayCredentials;
import com.github.binarywang.wxpay.v3.util.PemUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.util.Collections;
import java.util.Date;

/**
 * 微信代金券批次服务类
 **/

@Service
@Slf4j
public class WxCouponStocksService {

    @Autowired
    private WxProperties wxProperties;

    private static final String logPrefix = "微信卡券批次";

    /**
     * 创建微信代金券
     * @param awardCouponBo 卡券参数信息
     * @param mchId 可撤销商户号
     * @return stockId
     */
    public String createCouponStocks(AwardCouponBo awardCouponBo, String mchId) throws Exception{
        log.info("创建" + logPrefix + "进来的参数：{}", JSONUtil.toJsonStr(awardCouponBo));
        WxPayService wxPayService = getwxPayService();

        FavorStocksCreateRequest request = new FavorStocksCreateRequest();
        // 批次名称
        request.setStockName(awardCouponBo.getCouponName());
        // 使用说明
        FavorStocksCreateRequest.PatternInfo patternInfo = new FavorStocksCreateRequest.PatternInfo();
        patternInfo.setDescription(awardCouponBo.getRemark());
        request.setPatternInfo(patternInfo);
        // 归属商户号
        request.setBelongMerchant(wxPayService.getConfig().getMchId());
        // 开始时间
        request.setAvailableBeginTime(formatDate(awardCouponBo.getStartTime()));
        // 结束时间
        request.setAvailableEndTime(formatDate(awardCouponBo.getEndTime()));
        // 营销经费 true：免充值 false：预充值
        request.setNoCash(false);
        // 批次类型 NORMAL：固定面额满减券批次
        request.setStockType(StockTypeEnum.NORMAL);
        // 商户单据号
        request.setOutRequestNo(wxPayService.getConfig().getMchId() + DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss"));
        //发放规则
        FavorStocksCreateRequest.StockUseRule stockUseRule = new FavorStocksCreateRequest.StockUseRule();
        // 发放总上限
        stockUseRule.setMaxCoupons(awardCouponBo.getCouponNum());
        // 单个用户可领个数
        stockUseRule.setMaxCouponsPerUser(awardCouponBo.getEveryoneMaxNum());
        // 是否开启自然人限制
        stockUseRule.setNaturalPersonLimit(true);
        // 是否开启防刷拦截
        stockUseRule.setPreventApiAbuse(true);
        // 总预算
        stockUseRule.setMaxAmount(awardCouponBo.getCouponAmount());
        request.setStockUseRule(stockUseRule);
        //核销规则
        FavorStocksCreateRequest.CouponUseRule couponUseRule = new FavorStocksCreateRequest.CouponUseRule();
        // 固定面额满减券使用规则 stock_type为NORMAL时必填
        FavorStocksCreateRequest.FixedNormalCoupon fixedNormalCoupon = new FavorStocksCreateRequest.FixedNormalCoupon();
        // 面额 单位：分
        fixedNormalCoupon.setCouponAmount(awardCouponBo.getCouponPrice());
        // 门槛 单位：分
        fixedNormalCoupon.setTransactionMinimum(awardCouponBo.getPayAmount());
        couponUseRule.setFixedNormalCoupon(fixedNormalCoupon);
        // 是否可叠加其他优惠
        couponUseRule.setCombineUse(true);
        // 可核销商户号
        couponUseRule.setAvailableMerchants(Collections.singletonList(mchId));
        // 指定付款方式 银行卡编码 PSBC_DEBIT邮储银行(不支持)
//        couponUseRule.setLimitPay(Collections.singletonList("PSBC_DEBIT"));
        request.setCouponUseRule(couponUseRule);

        FavorStocksCreateResult result = wxPayService.getMarketingFavorService().createFavorStocksV3(request);
        String stockId = result.getStockId();

        log.info("stockId: {}", stockId);
        return stockId;
    }

    /**
     * 激活卡券批次
     * @param stockId 批次号
     * @return stockId
     */
    public String activateCouponStocks(String stockId) throws Exception {
        log.info("激活" + logPrefix + "进来的参数stockId：{}", stockId);
        WxPayService wxPayService = getwxPayService();

        FavorStocksSetRequest request = new FavorStocksSetRequest();
        request.setStockCreatorMchid(wxPayService.getConfig().getMchId());

        FavorStocksStartResult result = wxPayService.getMarketingFavorService().startFavorStocksV3(stockId, request);

        log.info("激活批次Id: {}", result.getStockId());
        return result.getStockId();
    }

    /**
     * 暂停卡券批次详情
     * @param stockId 批次号
     * @return stockId
     */
    public String pauseCouponStocks(String stockId) throws Exception {
        log.info("暂停" + logPrefix + "进来的参数stockId：{}", stockId);
        WxPayService wxPayService = getwxPayService();

        FavorStocksSetRequest request = new FavorStocksSetRequest();
        request.setStockCreatorMchid(wxPayService.getConfig().getMchId());

        FavorStocksPauseResult result = wxPayService.getMarketingFavorService().pauseFavorStocksV3(stockId, request);

        log.info("暂停批次Id: {}", result.getStockId());
        return result.getStockId();
    }

    /**
     * 重启卡券批次详情
     * @param stockId 批次号
     * @return stockId
     */
    public String restartCouponStocks(String stockId) throws Exception {
        log.info("重启" + logPrefix + "进来的参数stockId：{}", stockId);
        WxPayService wxPayService = getwxPayService();

        FavorStocksSetRequest request = new FavorStocksSetRequest();
        request.setStockCreatorMchid(wxPayService.getConfig().getMchId());

        FavorStocksRestartResult result = wxPayService.getMarketingFavorService().restartFavorStocksV3(stockId, request);

        log.info("重启批次Id: {}", result.getStockId());
        return result.getStockId();
    }

    /**
     * 条件查询批次列表
     * @return FavorStocksQueryResult
     */
    public FavorStocksQueryResult queryCouponStocks(Integer offSet, Integer limit, String startTime, String endTime, String status) throws Exception {
        log.info("条件查询" + logPrefix + "进来的参数offSet：{},limit：{},startTime：{},endTime：{},status：{},", offSet, limit, startTime, endTime, status);

        WxPayService wxPayService = getwxPayService();

        FavorStocksQueryRequest request = new FavorStocksQueryRequest();
        // 页码
        request.setOffset(offSet);
        // 分页大小，最大10
        request.setLimit(limit);
        // 批次创建方商户号
        request.setStockCreatorMchid(wxPayService.getConfig().getMchId());
        request.setCreateStartTime(formatDate(startTime));
        request.setCreateEndTime(formatDate(endTime));
        // unactivated：未激活 audit：审核中 running：运行中 stoped：已停止 paused：暂停发放
        request.setStatus(status);

        FavorStocksQueryResult result = wxPayService.getMarketingFavorService().queryFavorStocksV3(request);

        log.info("批次列表: {}", JSONUtil.toJsonStr(result));
        return result;
    }

    /**
     * 查询卡券批次详情
     * @param stockId 批次号
     * @return FavorStocksGetResult
     */
    public FavorStocksGetResult getCouponStocks(String stockId) throws Exception {
        log.info("查询" + logPrefix + "详情进来的参数stockId：{}", stockId);

        WxPayService wxPayService = getwxPayService();
        FavorStocksGetResult result = wxPayService.getMarketingFavorService().getFavorStocksV3(stockId, wxPayService.getConfig().getMchId());

        log.info("批次详情: {}", JSONUtil.toJsonStr(result));
        return result;
    }

    /**
     * 查询可用商户列表
     * @param stockId 批次号
     * @param offset 页数
     * @param limit 条数
     * @return FavorStocksMerchantsGetResult
     */
    public FavorStocksMerchantsGetResult getStockMerchants(String stockId, Integer offset, Integer limit) throws Exception {
        log.info("查询" + logPrefix + "用商户列表进来的参数stockId：{},offset:{},limit:{}", stockId, offset, limit);

        WxPayService wxPayService = getwxPayService();

        FavorStocksMerchantsGetResult result = wxPayService.getMarketingFavorService().getFavorStocksMerchantsV3(stockId, wxPayService.getConfig().getMchId(), offset, limit);

        log.info("批次可用商户列表: {}", JSONUtil.toJsonStr(result));
        return result;
    }

    /**
     * 下载批次核销明细
     * @param stockId 批次号
     * @return url
     */
    public String getStockUseFlow(String stockId) throws Exception {
        log.info("下载" + logPrefix + "核销明细进来的参数stockId：{}", stockId);

        WxPayService wxPayService = getwxPayService();

        FavorStocksFlowGetResult result = wxPayService.getMarketingFavorService().getFavorStocksUseFlowV3(stockId);

        log.info("批次核销明细: {}", JSONUtil.toJsonStr(result));
        return result.getUrl();
    }

    /**
     * 下载批次退款明细
     * @param stockId 批次号
     * @return url
     */
    public String getStockRefundFlow(String stockId) throws Exception {
        log.info("下载" + logPrefix + "退款明细进来的参数stockId：{}", stockId);

        WxPayService wxPayService = getwxPayService();

        FavorStocksFlowGetResult result = wxPayService.getMarketingFavorService().getFavorStocksRefundFlowV3(stockId);

        log.info("批次退款明细: {}", JSONUtil.toJsonStr(result));
        return result.getUrl();
    }

    /**
     * 格式化时间
     * @param date String类型
     */
    public String formatDate(String date) {
        return DateUtil.format(DateUtil.parse(date), "yyyy-MM-dd'T'HH:mm:ssXXX");
    }

    /**
     * 格式化时间
     * @param date Date类型
     */
    public String formatDate(Date date) {
        return DateUtil.format(date, "yyyy-MM-dd'T'HH:mm:ssXXX");
    }

    /**
     * 获取微信服务参数
     * @return WxPayService
     */
    public WxPayService getwxPayService() {
        WxPayConfig wxPayConfig = new WxPayConfig();
        wxPayConfig.setMchId("1628242998");
        wxPayConfig.setApiV3Key("qazwSXEDCRFVTGBYHNUJMIKLOP12345a");
        wxPayConfig.setCertSerialNo("53e63aa87edd7c8811060ffed21f4b4e8ff61b80");
        wxPayConfig.setPrivateKeyPath("C:\\Users\\Administrator\\Desktop\\apiclient_key.pem");
        wxPayConfig.setPrivateCertPath("C:\\Users\\Administrator\\Desktop\\cert.pem");

        // 自动获取微信平台证书
        PrivateKey privateKey = null;
        try {
            privateKey = PemUtils.loadPrivateKey(Files.newInputStream(Paths.get(wxPayConfig.getPrivateKeyPath())));
        } catch (Exception e) {
            log.info("获取证书异常：{}", e.getMessage());
            e.printStackTrace();
        }
        AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                new WxPayCredentials(wxPayConfig.getMchId(), new PrivateKeySigner(wxPayConfig.getCertSerialNo(), privateKey)),
                wxPayConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8));
        wxPayConfig.setVerifier(verifier);

        WxPayService wxPayService = new WxPayServiceImpl();
        wxPayService.setConfig(wxPayConfig);
        return wxPayService;
    }




    /**
     * 获取微信服务参数
     * @return WxPayService
     */
    public WxPayService getWxPayServiceV() {
        WxPayConfig wxPayConfig = new WxPayConfig();
        wxPayConfig.setMchId(wxProperties.getMchId());
        wxPayConfig.setApiV3Key(wxProperties.getApiV3Key());
        wxPayConfig.setCertSerialNo(wxProperties.getCertSerialNo());
        wxPayConfig.setPrivateKeyPath(wxProperties.getPrivateKeyPath());
        wxPayConfig.setPrivateCertPath(wxProperties.getPrivateCertPath());

        // 自动获取微信平台证书
        PrivateKey privateKey = null;
        try {
            privateKey = PemUtils.loadPrivateKey(Files.newInputStream(Paths.get(wxPayConfig.getPrivateKeyPath())));
        } catch (Exception e) {
            log.info("获取证书异常：{}", e.getMessage());
            e.printStackTrace();
        }
        AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                new WxPayCredentials(wxPayConfig.getMchId(), new PrivateKeySigner(wxPayConfig.getCertSerialNo(), privateKey)),
                wxPayConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8));
        wxPayConfig.setVerifier(verifier);

        WxPayService wxPayService = new WxPayServiceImpl();
        wxPayService.setConfig(wxPayConfig);
        return wxPayService;
    }
}
